<?php

/*
 * This file is part of the php-phantomjs.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Ling\PhantomJs;

use Ling\PhantomJs\Exception\InvalidExecutableException;

/**
 * PHP PhantomJs
 *
 * @author Jon Wenmoth <contact@jonnyw.me>
 */
class Engine
{
    /**
     * Executable path.
     *
     * @var string
     * @access protected
     */
    protected string $path;

    /**
     * Debug flag.
     *
     * @var boolean
     * @access protected
     */
    protected bool $debug;

    /**
     * Cache flag.
     *
     * @var boolean
     * @access protected
     */
    protected bool $cache;

    /**
     * PhantomJs run options.
     *
     * @var array
     * @access protected
     */
    protected array $options;

    /**
     * Log info
     *
     * @var string
     * @access protected
     */
    protected string $log;

    /**
     * Internal constructor
     *
     * @access public
     * @return void
     */
    public function __construct()
    {
        $this->path = 'bin/phantomjs';
        $this->options = array();

        $this->debug = false;
        $this->cache = true;
    }

    /**
     * Get PhantomJs run command with
     * loader run options.
     *
     * @access public
     * @return string
     * @throws InvalidExecutableException
     */
    public function getCommand(): string
    {
        $path = $this->getPath();
        $options = $this->getOptions();

        $this->validateExecutable($path);

        if ($this->cache) {
            $options[] = '--disk-cache=true';
        }

        if ($this->debug) {
            $options[] = '--debug=true';
        }

        return sprintf('%s %s', $path, implode(' ', $options));
    }

    /**
     * Set path.
     *
     * @access public
     * @param string $path
     * @return Engine
     * @throws InvalidExecutableException
     */
    public function setPath(string $path): Engine
    {
        $this->validateExecutable($path);
        $this->path = $path;
        return $this;
    }

    /**
     * Get path.
     *
     * @access public
     * @return string
     */
    public function getPath(): string
    {
        return $this->path;
    }

    /**
     * Set PhantomJs run options.
     *
     * @access public
     * @param array $options
     * @return Engine
     */
    public function setOptions(array $options): Engine
    {
        $this->options = $options;

        return $this;
    }

    /**
     * Get PhantomJs run options.
     *
     * @access public
     * @return array
     */
    public function getOptions(): array
    {
        return $this->options;
    }

    /**
     * Add single PhantomJs run option.
     *
     * @access public
     * @param string $option
     * @return Engine
     */
    public function addOption(string $option): Engine
    {
        if (!in_array($option, $this->options)) {
            $this->options[] = $option;
        }

        return $this;
    }

    /**
     * Debug.
     *
     * @access public
     * @param boolean $doDebug
     * @return Engine
     */
    public function debug(bool $doDebug): Engine
    {
        $this->debug = $doDebug;

        return $this;
    }

    /**
     * Cache.
     *
     * @access public
     * @param boolean $doCache
     * @return Engine
     */
    public function cache(bool $doCache): Engine
    {
        $this->cache = $doCache;

        return $this;
    }

    /**
     * Log info.
     *
     * @access public
     * @param string $info
     * @return Engine
     */
    public function log(string $info): Engine
    {
        $this->log = $info;

        return $this;
    }

    /**
     * Get log info.
     *
     * @access public
     * @return string
     */
    public function getLog(): string
    {
        return $this->log;
    }

    /**
     * Clear log info.
     *
     * @access public
     * @return Engine
     */
    public function clearLog(): Engine
    {
        $this->log = '';

        return $this;
    }

    /**
     * Validate execuable file.
     *
     * @access private
     * @param string $file
     * @throws InvalidExecutableException
     */
    private function validateExecutable(string $file): void
    {
        if (!file_exists($file) || !is_executable($file)) {
            throw new InvalidExecutableException(sprintf('File does not exist or is not executable: %s', $file));
        }
    }
}
